package com.uzai.console.service.wechatprivate.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.uzai.common.enums.DeviceTypeEnum;
import com.uzai.common.enums.MessageFuncEnum;
import com.uzai.common.exception.BusinessException;
import com.uzai.common.msg.MsgDto;
import com.uzai.common.result.ResponseCode;
import com.uzai.common.utils.EsIndexName;
import com.uzai.console.common.utils.DateUtil;
import com.uzai.console.common.utils.DesensitizeUtil;
import com.uzai.console.common.utils.Tools;
import com.uzai.console.constant.Const;
import com.uzai.console.constant.ES.ESResult;
import com.uzai.console.constant.ES.ElasticsearchUtil;
import com.uzai.console.dto.rocketmq.friendrequest.AddUserApplyDto;
import com.uzai.console.dto.wechatprivate.friendrequest.FriendRequestIdListDto;
import com.uzai.console.dto.wechatprivate.friendrequest.FriendRequestQuery;
import com.uzai.console.entity.Device;
import com.uzai.console.entity.es.EsWechatReqUser;
import com.uzai.console.enums.FriendRequestScene;
import com.uzai.console.enums.QFriendRequestScene;
import com.uzai.console.service.device.DeviceService;
import com.uzai.console.service.rocketmq.NoticeMsgPushProducerService;
import com.uzai.console.service.wechatprivate.FriendRequestService;
import com.uzai.console.vo.wechatprivate.friendrequest.FriendRequestCountItemVo;
import com.uzai.console.vo.wechatprivate.friendrequest.FriendRequestInfoVo;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ValueCount;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 个人微信-好友请求
 * @author liuqi
 * @date 2021年08月13日 11:34
 */
@Service
public class FriendRequestServiceImpl implements FriendRequestService {

    Logger logger = LoggerFactory.getLogger(FriendRequestServiceImpl.class);

    @Autowired
    private ElasticsearchUtil elasticsearchUtil;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private NoticeMsgPushProducerService noticeMsgPushProducerService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询好友请求列表
     * @author liuqi
     * @date 2021/8/13 11:38
     * @param friendRequestQuery
     * @return null
     */
    public Page<FriendRequestInfoVo> findFriendRequestList(FriendRequestQuery friendRequestQuery, Boolean tuominFlag){

        logger.info("---查询个微好友请求列表---friendRequestQuery={}", JSONObject.toJSONString(friendRequestQuery));

        //根据机器人列表查询需要增加限制时间
        if(friendRequestQuery.getDeviceUniqueIdList() != null && friendRequestQuery.getSize() > 0){
            if (friendRequestQuery.getDeviceUniqueIdList().size() >= 100) {
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "机器人列表查询条件数量不能超过100个");
            }
        }

        //新建返回到页面的LIST对象
        List<FriendRequestInfoVo> friendRequestInfoVoList = new ArrayList<>();

        //执行分页查询对象
        Page<FriendRequestInfoVo> page = new Page<>();
        friendRequestQuery.convert(page);

        //ES查询
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //运营商ID
        boolQuery.must(QueryBuilders.termQuery("merId", Tools.getLong(friendRequestQuery.getMerId())));

        //个人微信好友请求
        boolQuery.must(QueryBuilders.termsQuery("deviceType", Lists.newArrayList(DeviceTypeEnum.DT_PC_WECHAT_VALUE, DeviceTypeEnum.DT_ANDROID_WECHAT_VALUE)));

        //高亮字段
        String highlightField = null;

        //机器人唯一id
        if(friendRequestQuery.getDeviceUniqueId() != null){
            boolQuery.must(QueryBuilders.termQuery("deviceUniqueId", friendRequestQuery.getDeviceUniqueId()));
        }

        //机器人唯一id列表
        if(friendRequestQuery.getDeviceUniqueIdList() != null && friendRequestQuery.getDeviceUniqueIdList().size() > 0){
            boolQuery.must(QueryBuilders.termsQuery("deviceUniqueId", friendRequestQuery.getDeviceUniqueIdList()));
        }

        //微信昵称
        if(StringUtils.isNotBlank(friendRequestQuery.getNickName())){
            boolQuery.must(QueryBuilders.matchQuery("nickName",friendRequestQuery.getNickName()));
            highlightField = "nickName";
        }

        //状态
        if(friendRequestQuery.getStatus() != null){
            boolQuery.must(QueryBuilders.termQuery("status",friendRequestQuery.getStatus()));
        }

        //来源
        if(friendRequestQuery.getScene() != null){
            boolQuery.must(QueryBuilders.termQuery("scene",friendRequestQuery.getScene()));
        }

        //性别
        if(friendRequestQuery.getGender() != null){
            boolQuery.must(QueryBuilders.termQuery("gender",friendRequestQuery.getGender()));
        }

        //查新开始时间
        if(friendRequestQuery.getReqTimeStart() != null){
            boolQuery.must(QueryBuilders.rangeQuery("reqTime").gte(friendRequestQuery.getReqTimeStart()));
        }

        //查新结束时间
        if(friendRequestQuery.getReqTimeEnd() != null){
            boolQuery.must(QueryBuilders.rangeQuery("reqTime").lte(friendRequestQuery.getReqTimeEnd()));
        }

        //新版查新开始时间
        if(friendRequestQuery.getReqTimeStartNew() != null){
            boolQuery.must(QueryBuilders.rangeQuery("reqTime").gte(friendRequestQuery.getReqTimeStartNew()));
        }

        //新版查新结束时间
        if(friendRequestQuery.getReqTimeEndNew() != null){
            boolQuery.must(QueryBuilders.rangeQuery("reqTime").lte(friendRequestQuery.getReqTimeEndNew()));
        }

        searchSourceBuilder.query(boolQuery);

        //排序
        //searchSourceBuilder.sort("status", SortOrder.ASC);
        searchSourceBuilder.sort("reqTime", SortOrder.DESC);

        //判断是否需要脱敏
        if(tuominFlag == null){
            tuominFlag = false;
        }
        String cmstype_requestusers_wxid_verified =  (String)redisTemplate.opsForValue().get(String.format(Const.SmsType.CMSTYPE_REQESTUSERS_WXID_VERIFIED, friendRequestQuery.getMerId()));
        if(StringUtils.isNotBlank(cmstype_requestusers_wxid_verified)){
            tuominFlag = false;
        }

        ESResult esResult = elasticsearchUtil.searchListData(EsIndexName.UZAI_WECHAT_REQ_USER, searchSourceBuilder, friendRequestQuery.getSize(), friendRequestQuery.getFromIndex(), null, null, highlightField, friendRequestQuery.getMerId());
        page.setTotal(esResult.getTotalHits());
        List<Map<String, Object>> dataList = esResult.getDataList();
        if(dataList != null && dataList.size() > 0){
            for (Map<String, Object> dataMp :dataList) {
                FriendRequestInfoVo friendRequestInfoVo  = JSONObject.parseObject(JSONObject.toJSONString(dataMp), FriendRequestInfoVo.class);
                //机器人唯一ID不为空
                if(friendRequestInfoVo.getDeviceUniqueId() != null && friendRequestInfoVo.getDeviceType() != null){
                    Device device = deviceService.findDeviceInfoByDeviceUniqueId(friendRequestInfoVo.getDeviceUniqueId(), DeviceTypeEnum.getById(friendRequestInfoVo.getDeviceType()).getKey(), friendRequestInfoVo.getMerId());
                    if(device != null){
                        friendRequestInfoVo.setDeviceName(device.getDeviceName());
                        friendRequestInfoVo.setDeviceId(device.getDeviceId());
                        friendRequestInfoVo.setDeviceRemark(device.getDeviceRemark());
                    }
                }

                //是否脱敏处理
                if(tuominFlag){
                    friendRequestInfoVo.setWxid(DesensitizeUtil.around(Tools.getStr(friendRequestInfoVo.getWxid()),3,3));
                }

                friendRequestInfoVoList.add(friendRequestInfoVo);
            }
        }

        //返回到页面分页对象
        page.setRecords(friendRequestInfoVoList);
        //将分页信息复制到返回到页面的分页MO当中
        return page;
    }

    private static void buildFriendRequestQuery(FriendRequestQuery query, BoolQueryBuilder boolQuery) {
        //运营商ID
        boolQuery.must(QueryBuilders.termQuery("merId", Tools.getLong(query.getMerId())));
        if (StringUtils.equals(query.getDeviceType(), DeviceTypeEnum.DT_PC_WECHAT.getKey())) {
            boolQuery.must(QueryBuilders.rangeQuery("deviceType").lt(2));
        } else if (StringUtils.equals(query.getDeviceType(), DeviceTypeEnum.DT_WORK_WECHAT.getKey())) {
            boolQuery.must(QueryBuilders.termsQuery("deviceType", Lists.newArrayList(DeviceTypeEnum.DT_WORK_WECHAT.getId(), DeviceTypeEnum.DT_ANDROID_WORK_WECHAT.getId())));
        }
        boolQuery.must(QueryBuilders.termsQuery("deviceUniqueId", query.getDeviceUniqueIds()));
        // 只查询已通过的
        // boolQuery.must(QueryBuilders.termQuery("status", 1));
        //来源
        if (ObjectUtils.isNotEmpty(query.getScenes())) {
            boolQuery.must(QueryBuilders.termsQuery("scene", query.getScenes()));
            // boolQuery.must(QueryBuilders.termQuery("scene", query.getScene()));
        }
        //查新结束时间
        if (Objects.nonNull(query.getReqTimeStart()) && Objects.nonNull(query.getReqTimeEnd())) {
            boolQuery.must(QueryBuilders.rangeQuery("reqTime").from(query.getReqTimeStart()).to(query.getReqTimeEnd()));
        }
    }

    @Override
    public List<FriendRequestCountItemVo> listFriendRequestCount(FriendRequestQuery query) {

        //ES查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //运营商ID
        buildFriendRequestQuery(query, boolQuery);

        TermsAggregationBuilder deviceUniqueIdAgg = AggregationBuilders.terms("deviceUniqueId").field("deviceUniqueId").size(10000);

        deviceUniqueIdAgg.subAggregation(
                AggregationBuilders.terms("scene").field("scene").size(10000).subAggregation(AggregationBuilders.count("count").field("wxid")).size(10000)
        );

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(boolQuery)
                .addAggregation(deviceUniqueIdAgg).build();

        logger.info("query dsl: {}", build.getQuery());
        logger.info("query agg: {}", build.getAggregations());
        SearchHits<EsWechatReqUser> search = elasticsearchUtil.elasticsearchRestTemplate().search(build, EsWechatReqUser.class);
        List<FriendRequestCountItemVo> records = new ArrayList<>();

        List<Long> existsDeviceUniqueIds = new ArrayList<>();

        // 处理聚合结果
        Terms deviceUniqueIdTerms = (Terms) search.getAggregations().asMap().get("deviceUniqueId");
        for (Terms.Bucket robotIdBucket : deviceUniqueIdTerms.getBuckets()) {
            FriendRequestCountItemVo friendRequestCountVo = new FriendRequestCountItemVo();

            Terms sceneTerms = (Terms) robotIdBucket.getAggregations().asMap().get("scene");
            for (Terms.Bucket sceneBucket : sceneTerms.getBuckets()) {
                String scene = sceneBucket.getKeyAsString();
                ValueCount count = (ValueCount) sceneBucket.getAggregations().asMap().get("count");
                String sceneName = "";
                Integer sceneInt = Integer.valueOf(scene);
                if (StringUtils.equals(query.getDeviceType(), DeviceTypeEnum.DT_PC_WECHAT.getKey())) {
                    sceneName = ObjectUtils.defaultIfNull(FriendRequestScene.getById(sceneInt), FriendRequestScene.UN_KNOW).getLabel();
                }
                // 企业微信
                else if (StringUtils.equals(query.getDeviceType(), DeviceTypeEnum.DT_WORK_WECHAT.getKey())) {
                    sceneName = ObjectUtils.defaultIfNull(QFriendRequestScene.getById(sceneInt), QFriendRequestScene.UN_KNOW).getLabel();
                }
                FriendRequestCountItemVo.SceneInfo sceneInfo = FriendRequestCountItemVo.sceneInfo(sceneInt, sceneName, (int) count.getValue());
                friendRequestCountVo.getSceneList().add(sceneInfo);
            }
            long deviceUniqueId = Long.parseLong(robotIdBucket.getKeyAsString());

            friendRequestCountVo.setDeviceUniqueId(deviceUniqueId);
            existsDeviceUniqueIds.add(deviceUniqueId);
            friendRequestCountVo.calculateTotal();
            records.add(friendRequestCountVo);
        }
        if (records.size() >= query.getDeviceUniqueIds().size()) {
            return records;
        }
        // 补齐没有数据的机器人ID
        for (Long deviceUniqueId : query.getDeviceUniqueIds()) {
            if (existsDeviceUniqueIds.contains(deviceUniqueId)) {
                continue;
            }
            FriendRequestCountItemVo record = new FriendRequestCountItemVo();
            record.setDeviceUniqueId(deviceUniqueId);
            records.add(record);
        }
        return records;
    }

    @Override
    public List<FriendRequestCountItemVo> countFriendApplyAndPassCount(FriendRequestQuery query) {

        //ES查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //运营商ID
        buildFriendRequestQuery(query, boolQuery);

        TermsAggregationBuilder deviceUniqueIdAgg = AggregationBuilders.terms("deviceUniqueId").field("deviceUniqueId").size(10000);

        deviceUniqueIdAgg.subAggregation(AggregationBuilders.count("count").field("wxid")).size(10000);
        deviceUniqueIdAgg.subAggregation(AggregationBuilders.terms("status").field("status").size(10000).subAggregation(AggregationBuilders.count("count").field("wxid")).size(10000));

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(boolQuery).addAggregation(deviceUniqueIdAgg).build();

        //logger.info("query dsl: {}", build.getQuery());
        //logger.info("query agg: {}", build.getAggregations());
        SearchHits<EsWechatReqUser> search = elasticsearchUtil.elasticsearchRestTemplate().search(build, EsWechatReqUser.class);
        List<FriendRequestCountItemVo> records = new ArrayList<>();

        List<Long> existsDeviceUniqueIds = new ArrayList<>();

        // 处理聚合结果
        Terms deviceUniqueIdTerms = (Terms) search.getAggregations().asMap().get("deviceUniqueId");
        for (Terms.Bucket robotIdBucket : deviceUniqueIdTerms.getBuckets()) {
            FriendRequestCountItemVo friendRequestCountVo = new FriendRequestCountItemVo();
            // 申请总数
            ValueCount applyCount = (ValueCount) robotIdBucket.getAggregations().asMap().get("count");
            friendRequestCountVo.setApplyCount((int) applyCount.getValue());
            // 遍历每个状态的
            Terms statusTerms = (Terms) robotIdBucket.getAggregations().asMap().get("status");
            for (Terms.Bucket statusBucket : statusTerms.getBuckets()) {
                String scene = statusBucket.getKeyAsString();
                // 通过
                if (!StringUtils.equals(scene, "1")) {
                    continue;
                }
                ValueCount passCount = (ValueCount) statusBucket.getAggregations().asMap().get("count");
                friendRequestCountVo.setPassCount((int) passCount.getValue());
            }
            long deviceUniqueId = Long.parseLong(robotIdBucket.getKeyAsString());

            friendRequestCountVo.setDeviceUniqueId(deviceUniqueId);
            existsDeviceUniqueIds.add(deviceUniqueId);
            records.add(friendRequestCountVo);
        }
        if (records.size() >= query.getDeviceUniqueIds().size()) {
            return records;
        }
        // 补齐没有数据的机器人ID
        for (Long deviceUniqueId : query.getDeviceUniqueIds()) {
            if (existsDeviceUniqueIds.contains(deviceUniqueId)) {
                continue;
            }
            FriendRequestCountItemVo record = new FriendRequestCountItemVo();
            record.setDeviceUniqueId(deviceUniqueId);
            records.add(record);
        }
        return records;
    }

    @Override
    public Map<Long, Integer> totalFriendRequestCount(FriendRequestQuery query) {

        //ES查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 构建查询条件
        buildFriendRequestQuery(query, boolQuery);

        TermsAggregationBuilder deviceUniqueIdAgg = AggregationBuilders.terms("deviceUniqueId").field("deviceUniqueId").size(10000).subAggregation(AggregationBuilders.count("count").field("wxid")).size(10000);

        NativeSearchQuery build = new NativeSearchQueryBuilder().withQuery(boolQuery).addAggregation(deviceUniqueIdAgg).build();

        logger.info("totalFriendRequestCount query dsl: {}", build.getQuery());
        logger.info("totalFriendRequestCount query agg: {}", build.getAggregations());
        SearchHits<EsWechatReqUser> search = elasticsearchUtil.elasticsearchRestTemplate().search(build, EsWechatReqUser.class);

        // 处理聚合结果
        Terms deviceUniqueIdTerms = (Terms) search.getAggregations().asMap().get("deviceUniqueId");
        Map<Long, Integer> result = new HashMap<>();
        for (Terms.Bucket robotIdBucket : deviceUniqueIdTerms.getBuckets()) {
            long deviceUniqueId = Long.parseLong(robotIdBucket.getKeyAsString());
            ValueCount count = (ValueCount) robotIdBucket.getAggregations().asMap().get("count");

            result.put(deviceUniqueId, ObjectUtils.defaultIfNull((int) count.getValue(), 0));
        }
        return result;
    }

    /**
     * 删除
     *
     * @param friendRequestIdListDto
     * @return null
     * @author liuqi
     * @date 2021/8/13 11:38
     */
    @Transactional
    public void deleteFriendRequest(FriendRequestIdListDto friendRequestIdListDto) {

        List<String> idList = friendRequestIdListDto.getIdList();
        if(idList == null && idList.size() == 0){
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "id不能为空");
        }
        try {
            for (String id : idList) {
                elasticsearchUtil.deleteDataById(EsIndexName.UZAI_WECHAT_REQ_USER,id);
            }

            //解决ES延时删除
            Thread.sleep(1000);

        }catch (Exception e){
            logger.error("ES删除好友请求出现异常,index="+ EsIndexName.UZAI_WECHAT_REQ_USER);
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "删除失败");
        }
    }


    /**
     * 通过好友请求
     * @author liuqi
     * @date 2021/8/13 11:38
     * @param friendRequestIdListDto
     * @return null
     */
    @Transactional
    public void addFriendRequest(FriendRequestIdListDto friendRequestIdListDto){

        List<String> idList = friendRequestIdListDto.getIdList();
        if(idList == null && idList.size() == 0){
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "id不能为空");
        }
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("status",1); //通过
            jsonObject.put("updateTime", DateUtil.getNowTime());
            for (String id : idList) {
                //查询微信ID
                Map<String,Object> wxidMap = elasticsearchUtil.searchDataById(EsIndexName.UZAI_WECHAT_REQ_USER, id, null);
                if(wxidMap != null){
                    //修改状态
                    elasticsearchUtil.updateDataById(jsonObject, EsIndexName.UZAI_WECHAT_REQ_USER, id);
                    //发送MQ消息
                    MsgDto<AddUserApplyDto> msgDto = new MsgDto<>();
                    AddUserApplyDto addUserApplyDto = new AddUserApplyDto();
                    EsWechatReqUser esWechatReqUser = JSONObject.parseObject(JSONObject.toJSONString(wxidMap), EsWechatReqUser.class);
                    addUserApplyDto.setWxid(esWechatReqUser.getWxid());
                    addUserApplyDto.setNickName(esWechatReqUser.getNickName());
                    addUserApplyDto.setExtContent(esWechatReqUser.getExt());
                    msgDto.setContent(addUserApplyDto);
                    msgDto.setId(IdWorker.getId());
                    msgDto.setDeviceType(esWechatReqUser.getDeviceType());
                    msgDto.setDeviceUniqueId(esWechatReqUser.getDeviceUniqueId());
                    msgDto.setMerId(esWechatReqUser.getMerId());
                    msgDto.setMsgType(MessageFuncEnum.PASS_ADD_USER_APPLY.getValue());
                    noticeMsgPushProducerService.addFriendRequest(msgDto);
                }
            }
        }catch (Exception e){
            logger.error("ES通过请求出现异常,index="+ EsIndexName.UZAI_WECHAT_REQ_USER);
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "通过好友请求失败");
        }
    }

    /**
     * 忽略好友请求
     * @author liuqi
     * @date 2021/8/13 11:38
     * @param friendRequestIdListDto
     * @return null
     */
    @Transactional
    public void passFriendRequest(FriendRequestIdListDto friendRequestIdListDto){

        List<String> idList = friendRequestIdListDto.getIdList();
        if(idList == null && idList.size() == 0){
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "id不能为空");
        }
        try {

            Integer now = DateUtil.getNowTime();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("status",2); //忽略
            jsonObject.put("updateTime", now);
            jsonObject.put("ignoreTime", now);

            for (String id : idList) {
                elasticsearchUtil.updateDataById(jsonObject, EsIndexName.UZAI_WECHAT_REQ_USER, id);
            }
        }catch (Exception e){
            logger.error("ES通过请求出现异常,index="+ EsIndexName.UZAI_WECHAT_REQ_USER);
            throw  new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "忽略好友请求失败");
        }
    }



}
